# coding=utf-8
import json, pickle, requests, traceback
from app.extensions import db, log
from datetime import date, datetime
from flask import request
from functools import wraps
from config import BaseConfig


def serialize(obj):
    return pickle.dumps(obj = obj, protocol = 0)


def deserialize(str):
    return pickle.loads(str = str)


class ComplexEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(obj, date):
            return obj.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, obj)


class JsonEncoder(ComplexEncoder):
    def __init__(self):
        pass


def recursive_json_loads(data):
    if isinstance(data, list):
        return [recursive_json_loads(i) for i in data]
    elif isinstance(data, tuple):
        return tuple([recursive_json_loads(i) for i in data])
    elif isinstance(data, dict):
        return Storage({recursive_json_loads(k): recursive_json_loads(data[k]) for k in data.keys()})
    else:
        try:
            obj = json.loads(data)
            if obj == data:
                return data
        except:
            return data
        return recursive_json_loads(obj)


class Storage(dict):
    """
    A Storage object is like a dictionary except `obj.foo` can be used
    in addition to `obj['foo']`.
        >>> o = storage(a=1)
        >>> o.a
        1
        >>> o['a']
        1
        >>> o.a = 2
        >>> o['a']
        2
        >>> del o.a
        >>> o.a
        Traceback (most recent call last):
            ...
        AttributeError: 'a'
    """

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError as k:
            raise AttributeError(k)

    def __setattr__(self, key, value):
        self[key] = value

    def __delattr__(self, key):
        try:
            del self[key]
        except KeyError as k:
            raise AttributeError(k)

    def __repr__(self):
        return '<Storage ' + dict.__repr__(self) + '>'


class JsonFileUtil:
    @staticmethod
    def load(path):
        with open(path) as json_file:
            data = json.load(json_file)
            return data

def DbCommit():
    try:
        db.session.commit()
        log.info("============== db commit success ==============")
    except BaseException as e:
        _msg = e.message
        log.error("============== db commit error . %s ==============" % _msg)
        db.session.rollback()
        return {'success': False, 'msg': _msg}
    return {'success': True, 'msg': ""}


def checkToken(func):
    @wraps(func)
    def check(*args):
        try:
            printArgs(request)
            # 1.在白名单内的链接不需要校验token_id
            _urls = getConfigJson("url_with_out_auth")
            if str(request.url_rule) in _urls:
                return func(*args, login_user_id = None, login_user_name = None)
            # 2.其它工程需要校验
            _token_id = request.values['token_id']
            if _token_id is None:
                _msg = "%s tokenid is empty"
                log.error("============== %s %s ==============" % (request.url_rule, _msg))
                return {'success': False, 'msg': _msg}
            _url = '%s?token_id=%s' % (BaseConfig.BEETLE_AUTH_URL, _token_id)
            _obj = recursive_json_loads(requests.get(url = _url).content)
            if _obj['success']:
                _data = _obj['data']
                log.info("============== %s : username is %s ==============" % (request.url_rule, _data['account']))
                # login_user_name  当用户的realname存在时,使用realname,否则使用account
                if _data['realname'] is None:
                    return func(*args, login_user_id = _data['id'], login_user_name = _data['account'])
                else:
                    return func(*args, login_user_id = _data['id'], login_user_name = _data['realname'])
            else:
                _msg = _obj['msg']
                log.error("============== %s %s ==============" % (request.url_rule, _msg))
                return {'success': False, 'msg': _msg}
        except BaseException:
            _msg = "get tokeid error"
            log.error("============== %s %s ==============" % (request.url_rule, _msg))
            log.error(traceback.format_exc())
            return {'success': False, 'msg': _msg}

    return check

def printArgs(request):
    _token_id = request.values['token_id']
    args = request.values
    for key in args:
        if key != 'token_id':
            log.info("============== %s : token_id is %s . %s is %s ==============" % (
                request.url_rule, _token_id, key, args[key]))
        else:
            log.info("============== %s : token_id is %s ==============" % (request.url_rule, _token_id))

def getConfigJson(key):
    from jsonFileUtil import getJsonFile
    _json = getJsonFile("%s/data/config.json" % BaseConfig.PROJECT_ROOT)
    return _json[key]